import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FullStackCodeGenerator extends JFrame {
    // Basic settings panel components
    private JTextField basePackageField;
    private JTextField moduleNameField;
    private JTextField tableNameField;
    private JCheckBox generateEntity, generateMapper, generateService, generateController, generateXml;
    
    // Attribute settings panel components
    private JList<String> attributeList;
    private DefaultListModel<String> attributeModel;
    private JTextField attrNameField, attrTypeField, attrCommentField;
    
    // Generation options panel components
    private JCheckBox lombokSupport, swaggerSupport, mybatisPlusSupport;
    
    // Project path selection
    private JTextField projectPathField;

    public FullStackCodeGenerator() {
        initUI();
        initEventListeners();
    }
    
    private void initUI() {
        setTitle("Java Full Stack Code Generator");
        setSize(900, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        
        // Use TabbedPane to organize multiple configuration panels
        JTabbedPane tabbedPane = new JTabbedPane();
        
        // Basic settings panel
        JPanel baseSettingPanel = createBaseSettingPanel();
        tabbedPane.addTab("Basic Settings", baseSettingPanel);
        
        // Attribute settings panel
        JPanel attributePanel = createAttributePanel();
        tabbedPane.addTab("Attributes", attributePanel);
        
        // Generation options panel
        JPanel optionPanel = createOptionPanel();
        tabbedPane.addTab("Generation Options", optionPanel);
        
        // Project path panel
        JPanel pathPanel = createPathPanel();
        tabbedPane.addTab("Save Path", pathPanel);
        
        // Bottom generation button
        JButton generateBtn = new JButton("Generate Code");
        generateBtn.setFont(new Font("Arial", Font.BOLD, 16));
        generateBtn.setBackground(new Color(46, 139, 87));
        generateBtn.setForeground(Color.WHITE);
        
        // Main layout
        setLayout(new BorderLayout());
        add(tabbedPane, BorderLayout.CENTER);
        add(generateBtn, BorderLayout.SOUTH);
        
        // Button event
        generateBtn.addActionListener(e -> generateCode());
    }
    
    private JPanel createBaseSettingPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        
        // Base package
        gbc.gridx = 0;
        gbc.gridy = 0;
        panel.add(new JLabel("Base Package:"), gbc);
        
        gbc.gridx = 1;
        basePackageField = new JTextField("com.example.demo", 30);
        panel.add(basePackageField, gbc);
        
        // Module name
        gbc.gridx = 0;
        gbc.gridy = 1;
        panel.add(new JLabel("Module Name:"), gbc);
        
        gbc.gridx = 1;
        moduleNameField = new JTextField("user", 30);
        panel.add(moduleNameField, gbc);
        
        // Table name
        gbc.gridx = 0;
        gbc.gridy = 2;
        panel.add(new JLabel("Table Name:"), gbc);
        
        gbc.gridx = 1;
        tableNameField = new JTextField("sys_user", 30);
        panel.add(tableNameField, gbc);
        
        // Generation options
        gbc.gridx = 0;
        gbc.gridy = 3;
        panel.add(new JLabel("Generate Components:"), gbc);
        
        gbc.gridx = 1;
        JPanel generateOptionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        generateEntity = new JCheckBox("Entity Class");
        generateMapper = new JCheckBox("Mapper Interface");
        generateService = new JCheckBox("Service Layer");
        generateController = new JCheckBox("Controller Layer");
        generateXml = new JCheckBox("MyBatis XML");
        
        generateEntity.setSelected(true);
        generateMapper.setSelected(true);
        generateService.setSelected(true);
        generateController.setSelected(true);
        generateXml.setSelected(true);
        
        generateOptionsPanel.add(generateEntity);
        generateOptionsPanel.add(generateMapper);
        generateOptionsPanel.add(generateService);
        generateOptionsPanel.add(generateController);
        generateOptionsPanel.add(generateXml);
        
        panel.add(generateOptionsPanel, gbc);
        
        return panel;
    }
    
    private JPanel createAttributePanel() {
        JPanel panel = new JPanel(new BorderLayout());
        
        // Attribute list
        attributeModel = new DefaultListModel<>();
        attributeList = new JList<>(attributeModel);
        attributeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        JScrollPane listScrollPane = new JScrollPane(attributeList);
        
        // Attribute editing panel
        JPanel editPanel = new JPanel(new GridLayout(3, 2, 5, 5));
        editPanel.add(new JLabel("Attribute Name:"));
        attrNameField = new JTextField();
        editPanel.add(attrNameField);
        
        editPanel.add(new JLabel("Type:"));
        attrTypeField = new JTextField("String");
        editPanel.add(attrTypeField);
        
        editPanel.add(new JLabel("Comment:"));
        attrCommentField = new JTextField();
        editPanel.add(attrCommentField);
        
        // Button panel
        JPanel btnPanel = new JPanel(new FlowLayout());
        JButton addBtn = new JButton("Add Attribute");
        JButton deleteBtn = new JButton("Delete Attribute");
        JButton clearBtn = new JButton("Clear All");
        
        btnPanel.add(addBtn);
        btnPanel.add(deleteBtn);
        btnPanel.add(clearBtn);
        
        // Add default attributes
        addDefaultAttributes();
        
        // Assemble the panel
        JPanel bottomPanel = new JPanel(new BorderLayout());
        bottomPanel.add(editPanel, BorderLayout.NORTH);
        bottomPanel.add(btnPanel, BorderLayout.SOUTH);
        
        panel.add(listScrollPane, BorderLayout.CENTER);
        panel.add(bottomPanel, BorderLayout.SOUTH);
        
        // Button events
        addBtn.addActionListener(e -> addAttribute());
        deleteBtn.addActionListener(e -> deleteAttribute());
        clearBtn.addActionListener(e -> clearAttributes());
        
        return panel;
    }
    
    private void addAttribute(String name, String type, String comment) {
        attributeModel.addElement(name + "|" + type + "|" + comment);
    }
    
    private void addDefaultAttributes() {
        addAttribute("id", "Long", "Primary Key");
        addAttribute("username", "String", "Username");
        addAttribute("password", "String", "Password");
        addAttribute("email", "String", "Email");
        addAttribute("createTime", "Date", "Create Time");
    }
    
    private void addAttribute() {
        String name = attrNameField.getText().trim();
        String type = attrTypeField.getText().trim();
        String comment = attrCommentField.getText().trim();
        
        if (!name.isEmpty() && !type.isEmpty()) {
            attributeModel.addElement(name + "|" + type + "|" + comment);
            attrNameField.setText("");
            attrCommentField.setText("");
            attrNameField.requestFocus();
        }
    }
    
    private void deleteAttribute() {
        int selectedIndex = attributeList.getSelectedIndex();
        if (selectedIndex != -1) {
            attributeModel.remove(selectedIndex);
        }
    }
    
    private void clearAttributes() {
        attributeModel.clear();
    }
    
    private JPanel createOptionPanel() {
        JPanel panel = new JPanel(new GridLayout(3, 1, 10, 10));
        panel.setBorder(new EmptyBorder(10, 10, 10, 10));
        
        // Lombok support
        lombokSupport = new JCheckBox("Enable Lombok Support (Auto-generate Getter/Setter/ToString)");
        lombokSupport.setSelected(true);
        
        // Swagger support
        swaggerSupport = new JCheckBox("Enable Swagger Support (API Documentation)");
        
        // MyBatis-Plus support
        mybatisPlusSupport = new JCheckBox("Enable MyBatis-Plus Support (Simplify CRUD Operations)");
        
        panel.add(lombokSupport);
        panel.add(swaggerSupport);
        panel.add(mybatisPlusSupport);
        
        return panel;
    }
    
    private JPanel createPathPanel() {
        JPanel panel = new JPanel(new BorderLayout(5, 5));
        
        projectPathField = new JTextField(System.getProperty("user.dir"), 50);
        JButton browseBtn = new JButton("Browse...");
        
        JPanel pathPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        pathPanel.add(new JLabel("Project Path:"));
        pathPanel.add(projectPathField);
        pathPanel.add(browseBtn);
        
        panel.add(pathPanel, BorderLayout.NORTH);
        
        // Add project structure preview
        JTextArea previewArea = new JTextArea(10, 50);
        previewArea.setEditable(false);
        previewArea.setText(generateProjectStructurePreview());
        JScrollPane scrollPane = new JScrollPane(previewArea);
        
        panel.add(new JLabel("Generated Project Structure:"), BorderLayout.WEST);
        panel.add(scrollPane, BorderLayout.CENTER);
        
        // Browse button event
        browseBtn.addActionListener(e -> browseDirectory());
        
        return panel;
    }
    
    private String generateProjectStructurePreview() {
        StringBuilder sb = new StringBuilder();
        sb.append("src/main/java/\n");
        sb.append("  └── com/example/demo/\n");
        sb.append("      ├── entity/\n");
        sb.append("      │   └── User.java\n");
        sb.append("      ├── mapper/\n");
        sb.append("      │   └── UserMapper.java\n");
        sb.append("      ├── service/\n");
        sb.append("      │   ├── IUserService.java\n");
        sb.append("      │   └── impl/\n");
        sb.append("      │       └── UserServiceImpl.java\n");
        sb.append("      └── controller/\n");
        sb.append("          └── UserController.java\n");
        sb.append("\n");
        sb.append("src/main/resources/\n");
        sb.append("  └── mapper/\n");
        sb.append("      └── UserMapper.xml\n");
        
        return sb.toString();
    }
    
    private void browseDirectory() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fileChooser.setDialogTitle("Select Project Directory");
        
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            projectPathField.setText(fileChooser.getSelectedFile().getAbsolutePath());
        }
    }
    
    private void initEventListeners() {
        // Add more event listeners if needed
    }
    
    private void generateCode() {
        // Collect user input
        String basePackage = basePackageField.getText().trim();
        String moduleName = moduleNameField.getText().trim();
        String tableName = tableNameField.getText().trim();
        
        // Check required inputs
        if (basePackage.isEmpty() || moduleName.isEmpty() || tableName.isEmpty()) {
            JOptionPane.showMessageDialog(this, "Please fill in the base package, module name, and table name", "Warning", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        // Check attribute list
        if (attributeModel.size() == 0) {
            JOptionPane.showMessageDialog(this, "Please add at least one attribute", "Warning", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        // Collect attribute information
        List<Map<String, String>> attributes = new ArrayList<>();
        for (int i = 0; i < attributeModel.size(); i++) {
            String[] parts = attributeModel.getElementAt(i).split("\\|");
            Map<String, String> attr = new HashMap<>();
            attr.put("name", parts[0]);
            attr.put("type", parts[1]);
            attr.put("comment", parts.length > 2 ? parts[2] : "");
            attributes.add(attr);
        }
        
        // Convert module name to camel case
        String className = toCamelCase(moduleName, true);
        String lowerClassName = toCamelCase(moduleName, false);
        
        // Create code generator
        CodeGenerator generator = new CodeGenerator(
            basePackage, 
            className, 
            lowerClassName, 
            tableName, 
            attributes,
            lombokSupport.isSelected(),
            swaggerSupport.isSelected(),
            mybatisPlusSupport.isSelected()
        );
        
        // Generate code
        try {
            String projectPath = projectPathField.getText().trim();
            
            if (generateEntity.isSelected()) {
                String entityCode = generator.generateEntity();
                saveCodeToFile(entityCode, projectPath, "entity", className + ".java");
            }
            
            if (generateMapper.isSelected()) {
                String mapperCode = generator.generateMapper();
                saveCodeToFile(mapperCode, projectPath, "mapper", className + "Mapper.java");
            }
            
            if (generateService.isSelected()) {
                String serviceInterfaceCode = generator.generateServiceInterface();
                saveCodeToFile(serviceInterfaceCode, projectPath, "service", "I" + className + "Service.java");
                
                String serviceImplCode = generator.generateServiceImpl();
                saveCodeToFile(serviceImplCode, projectPath, "service/impl", className + "ServiceImpl.java");
            }
            
            if (generateController.isSelected()) {
                String controllerCode = generator.generateController();
                saveCodeToFile(controllerCode, projectPath, "controller", className + "Controller.java");
            }
            
            if (generateXml.isSelected()) {
                String xmlCode = generator.generateMyBatisXml();
                saveCodeToFile(xmlCode, projectPath, "mapper", className + "Mapper.xml", true);
            }
            
            JOptionPane.showMessageDialog(this, "Code generation successful!", "Success", JOptionPane.INFORMATION_MESSAGE);
        } catch (Exception e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Code generation failed: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    private void saveCodeToFile(String code, String projectPath, String packageDir, String fileName, boolean isResource) throws IOException {
        // Convert package name to directory structure
        String packagePath = packageDir.replace(".", File.separator);
        
        // Determine full path
        String fullPath;
        if (isResource) {
            fullPath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + 
                      "resources" + File.separator + packagePath;
        } else {
            fullPath = projectPath + File.separator + "src" + File.separator + "main" + File.separator + 
                      "java" + File.separator + packagePath.replace(".", File.separator);
        }
        
        // Create directory
        File dir = new File(fullPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        // Save file
        File file = new File(dir, fileName);
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(code);
        }
    }
    
    private void saveCodeToFile(String code, String projectPath, String packageDir, String fileName) throws IOException {
        saveCodeToFile(code, projectPath, packageDir, fileName, false);
    }
    
    // Convert to camel case
    private String toCamelCase(String input, boolean firstUpper) {
        String[] parts = input.split("_");
        StringBuilder result = new StringBuilder();
        
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i].toLowerCase();
            if (i > 0 || firstUpper) {
                result.append(part.substring(0, 1).toUpperCase());
                result.append(part.substring(1));
            } else {
                result.append(part);
            }
        }
        
        return result.toString();
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new FullStackCodeGenerator().setVisible(true));
    }
}